#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：idi_mes 
@File    ：input_vehicle_cell.py
@IDE     ：PyCharm 
@Date    ：9/26/24 9:02 AM 
"""
import json
from typing import Dict, List, Union, Tuple

from mg_app_framework import MesCode, get_logger, get_organization

from common.basic_mongo import get_retrospect_collection, get_mongo_collection
from common.basic_redis import get_redis_conn
from common.constant import RetrospectType
from common.retrospect_operate.handle import publish_retrospect_nodes
from prod_ctrl_service.tool.tool import check_cell_sn_consistent, check_repeat_in_or_out, get_time, batch_make_retros_in


async def check_input_vehicle_cell(params: Dict[str, Union[str, List[Dict[str, str]]]]) \
        -> Dict[str, str]:
    """
    MES系统验证上位机上传的电芯码和MES记录的一致、且托盘码内所有电芯符合进站条件
    :param params:{
               "call_id":"JQ00386",  #接口调用方认证ID, string
               "trace_id":"8941d16b-0581-4e68-8940-a651afff4282",  #接口调用ID, string
               "upperpc_code": "UP011",    #上位机编码, string
               "user_code":"Y001",  #员工编码, string
               "equip_code":"ZP001",  # 设备编码, string
               "process_code":"2050",   # 工序编码, string, 必输
               "vehicle_no":"20001",   #载具编码, string, Y, MES和上位机统一编码
               "cell_list": [    # 电芯列表, 数组, Y
                  {
                     "cell_sn": "WW202408140001",   # 电芯码, string, Y
                     "slot_no": "11"       # 通道号, string
                  },
                  {
                     "cell_sn": "WW202408140002",
                     "slot_no": "12"
                  }
               ]
            }
    :return:
    """
    error_msg = ""
    device_code = params.get("equip_code")
    process_code = params.get("process_code")
    vehicle_no = params.get("vehicle_no")
    cell_list = params.get("cell_list")
    cell_sn_list = [rec["cell_sn"] for rec in cell_list]
    # 对比托盘码在数据库中绑定的电芯码是否与入参中的电芯码一致
    if_consistent, check_result, cell_sn_list_in_db = await check_cell_sn_consistent(vehicle_no, cell_sn_list)
    if not if_consistent:
        return check_result

    # 通过bom信息校验当前工序工单状态
    rd_conn = get_redis_conn()
    ts_key = f"workorder_mgm~{device_code}"
    bom_info = await rd_conn.get(ts_key)
    bom_info = json.loads(bom_info)
    workorder_status = bom_info.get("workorder_status")
    if workorder_status != "on_work":
        error_msg += f"当前工序无生产中工单;"

    # 当前工序重码校验
    qr_code_has_used = await check_repeat_in_or_out(
        procedure_code=process_code, qr_code_list=cell_sn_list_in_db, op_type=RetrospectType.PRODUCT_IN
    )
    if qr_code_has_used:
        error_msg += f"下列电芯码重复进站:{qr_code_has_used};"

    # 前工序产出追溯信息校验
    pre_procedure_code: list = bom_info.get("pre_procedure_code", [])
    no_last_retros_code, no_check_result = await get_last_retrospect(
        last_procedure_code_list=pre_procedure_code, qr_code_list=cell_sn_list_in_db
    )
    if no_last_retros_code:
        error_msg += f"下列电芯码前工序没有产出追溯信息:{no_last_retros_code};"
    if no_check_result:
        error_msg += f"下列电芯码前工序产出追溯信息'不合格':{no_last_retros_code};"

    # todo Marking校验, marking相关功能未开发，等待开发后补充marking校验功能

    if error_msg:
        result = {
            "code": MesCode.fail,  # 接口应答状态代码, success：成功; fail：失败, string
            "data": {},  # 接口返回结果描述, json数组, 本接口不需要返回数据，返回null
            "info": error_msg,  # 接口返回信息描述, 如果为fail, 则为fail的异常描述信息, string
        }
        return result

    work_order = bom_info.get("workorder_code")
    insert_data_list = batch_make_retros_in(wip_list=cell_sn_list_in_db, work_order=work_order)

    try:
        for rec_item in insert_data_list:
            await publish_retrospect_nodes(device_code=device_code, retrospect_items=[rec_item])
        get_logger().info(f"码值{cell_sn_list_in_db}进站追溯数据已建立")
    except ValueError as e:
        error_msg += str(e)

    if error_msg:
        result = {
            "code": MesCode.fail,  # 接口应答状态代码, success：成功; fail：失败, string
            "data": {},  # 接口返回结果描述, json数组, 本接口不需要返回数据，返回null
            "info": error_msg,  # 接口返回信息描述, 如果为fail, 则为fail的异常描述信息, string
        }
        return result

    # 在制品进站的入参每一次调用成功后存储
    input_data = {
        "call_id": params.get("call_id"),  # 接口调用方认证ID, string
        "trace_id": params.get("trace_id"),  # 接口调用ID, string
        "upperpc_code": params.get("upperpc_code"),  # 上位机编码, string
        "user_code": params.get("user_code"),  # 员工编码, string
        "equip_code": params.get("equip_code"),  # 设备编码, string
        "process_code": params.get("process_code"),  # 工序编码, string, 必输
        "vehicle_no": params.get("vehicle_no"),  # 载具编码, string, Y, MES和上位机统一编码
        "cell_list": params.get("cell_list"),  # 电芯列表, 数组, Y
        "time": get_time()
    }
    await insert_data(input_data)

    result = {
        "code": MesCode.success,  # 接口应答状态代码, success：成功; fail：失败, string
        "data": {},  # 接口返回结果描述, json数组, 本接口不需要返回数据，返回null
        "info": "OK",  # 接口返回信息描述, 如果为fail, 则为fail的异常描述信息, string
    }

    return result


async def get_last_retrospect(last_procedure_code_list: list, qr_code_list: list) \
        -> Tuple[List, List]:
    """
    获取入参中电芯码在追溯表中前一道工序上的产出信息
    :param last_procedure_code_list:
    :param qr_code_list:
    :return:
    """
    qr_code_map = {rec: rec for rec in qr_code_list}
    pipeline = [
        {
            "$match": {
                "qr_code": {"$in": qr_code_list},
                "procedure_code": {"$in": last_procedure_code_list},
                "op_type": RetrospectType.PRODUCT_OUT,
                "is_delete": False,
            }
        },
        {"$sort": {"op_time": -1}},
        {"$group": {"_id": "$qr_code", "latestDocument": {"$first": "$$ROOT"}}},
    ]
    collection = get_retrospect_collection()
    result, check_no_qualify_result = {}, []
    async for rec in collection.aggregate(pipeline):
        qr_code = rec["_id"]
        document = rec["latestDocument"]
        result.update({qr_code: document})
        if document.get("check_result") == "不合格":
            check_no_qualify_result.append(qr_code)
        qr_code_map.pop(qr_code)  # 如果前道工序有该条码的产出(out)追溯信息，则从字典中pop该条码，最终字典中剩余的就是前道工序没有产出信息的条码

    return list(qr_code_map.keys()), check_no_qualify_result


async def insert_data(data):
    """
    登记当前投料蓝胶码/电芯码
    :param data:
    :return:
    """
    collection = get_mongo_collection(
        database_name=f"{get_organization()}_mes",
        collection_name=f"input_vehicle_cell_record",
    )
    await collection.insert_one(data)
